// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/sched.h>	/* current() */
#include <linux/preempt.h>	/* in_task() */
#include <linux/cred.h>		/* current_{e}{u,g}id() */
#include <linux/uidgid.h>	/* {from,make}_kuid() */

MODULE_LICENSE("GPL");         // 模块许可证
MODULE_AUTHOR("Jason Hu");     // 模块作者
MODULE_DESCRIPTION("print current task info");
MODULE_VERSION("0.01");         // 模块版本

static void get_ctx(void)
{
    /* Extract the task UID and EUID using helper methods provided */
	unsigned int uid = from_kuid(&init_user_ns, current_uid());
	unsigned int euid = from_kuid(&init_user_ns, current_euid());

	pr_info("\n");		/* shows mod & func names (due to the pr_fmt()!) */
	if (likely(in_task())) {
		pr_info("we're running in process context ::\n"
			" name        : %s\n"
			" PID         : %6d\n"
			" TGID        : %6d\n"
			" UID         : %6u\n"
			" EUID        : %6u (%s root)\n"
			" state       : %c\n"
			" current (ptr to our process context's task_struct) :\n"
			"               0x%pK (0x%px)\n"
			" stack start : 0x%pK (0x%px)\n",
			current->comm,
			/* always better to use the helper methods provided */
			task_pid_nr(current), task_tgid_nr(current),
			/* ... rather than using direct lookups:
			 * current->pid, current->tgid,
			 */
			uid, euid,
			(euid == 0 ? "have" : "don't have"),
			task_state_to_char(current),
			/* Printing addresses twice- via %pK and %px
			 * Here, by default, the values will typically be the same as
			 * kptr_restrict == 1 and we've got root.
			 */
			current, current, current->stack, current->stack);
		/* FIXME- doesn't work
		   if (task_state_to_char(current) == 'R')
		   pr_info("on virtual CPU? %s\n", (current->flags & PF_VCPU)?"yes":"no");
		 */
	} else
		pr_alert("Whoa! running in interrupt context [Should NOT Happen here!]\n");
}

static int __init current_init(void) {
    pr_info("Hello, Linux Module!\n");

    pr_info("task struct size: %ld\n", sizeof(struct task_struct));
    get_ctx();
    return 0;                   // 返回0表示模块加载成功
}

static void __exit current_exit(void) {
    pr_info("Goodbye, Linux Module!\n");
}

module_init(current_init);        // 指定模块加载时调用的函数
module_exit(current_exit);        // 指定模块卸载时调用的函数